package com.ruoyi.security.elevator.websocket;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.SpringUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.security.domain.*;
import com.ruoyi.security.domain.vo.ElevatorRealDataVo;
import com.ruoyi.security.domain.vo.ElevatorStatusPushVo;
import com.ruoyi.security.domain.vo.ElevatorStatusVo;
import com.ruoyi.security.elevator.mqtt.MqttGateway;
import com.ruoyi.security.elevator.util.ElevatorDataValue;
import com.ruoyi.security.service.IAfElevatorErrorService;
import com.ruoyi.security.service.IAfElevatorInfoService;
import com.ruoyi.security.service.IAfElevatorService;
import com.ruoyi.security.service.IElevatorSendService;
import com.ruoyi.security.service.impl.AfElevatorErrorServiceImpl;
import com.ruoyi.security.service.impl.AfElevatorInfoServiceImpl;
import com.ruoyi.security.service.impl.AfElevatorServiceImpl;
import com.ruoyi.security.service.impl.ElevatorSendServiceImpl;
import com.ruoyi.system.api.RemoteMsgSendService;
import com.ruoyi.system.api.domain.SysMsgAndTemplate;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.enums.ReadyState;
import org.java_websocket.handshake.ServerHandshake;

import java.net.URI;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.stream.Collectors;

@Slf4j
public class ElevatorWebsocketClient extends WebSocketClient {

    private RedisService redisService;

    private IAfElevatorInfoService elevatorInfoService;

    private IAfElevatorService elevatorService;

    private URI webUrl;
    private WebSocketClient client;

    private MqttGateway mqttGateway;

    private IAfElevatorErrorService afElevatorErrorService;

    private RemoteMsgSendService remoteMsgSendService;

    private IElevatorSendService sendService;

    public ElevatorWebsocketClient(URI serverUri) {
        super(serverUri);
        client = this;
        webUrl = serverUri;
        redisService = SpringUtils.getBean(RedisService.class);
        elevatorInfoService = SpringUtils.getBean(AfElevatorInfoServiceImpl.class);
        mqttGateway = SpringUtils.getBean(MqttGateway.class);
        elevatorService = SpringUtils.getBean(AfElevatorServiceImpl.class);
        afElevatorErrorService = SpringUtils.getBean(AfElevatorErrorServiceImpl.class);
        remoteMsgSendService = SpringUtils.getBean(RemoteMsgSendService.class);
        sendService = SpringUtils.getBean(ElevatorSendServiceImpl.class);
    }

    Timer timer = new Timer();
    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        log.info("websocket 打开");
        //WebSocketSessionManger.putSession(webUrl.toString(), client);
        //发送实时指令
        sendService.sendGetElevatorRealData("1",this);
    }

    @Override
    public void send(String text) {
        boolean open = isConnectOpen();
        if (open) {
            if(text != null){
                super.send(text);
            }
        }
    }
    /**
     * 在连接断开时尝试重连
     *
     * @return
     */
    public boolean isConnectOpen() {
        int t = 0;
        if (null == this) {
            return false;
        }
        // 连接断开
        while (!this.isOpen()) {
            try {
                log.info("重连服务器...");
                if (this.getReadyState().equals(ReadyState.NOT_YET_CONNECTED)) {
                    super.connectBlocking();
                    return true;
                } else if (this.getReadyState().equals(ReadyState.CLOSING) || this.getReadyState().equals(ReadyState.CLOSED)) {
                    super.reconnectBlocking();
                    return true;
                }
            } catch (Exception e) {
                log.error("reconnect error ", e);
            }
        }
        return true;
    }

    @Override
    public void onMessage(String s) {
        log.info("收到服务端数据--->{}", s);
        ElevatorResult<ElevatorData> result = JSON.parseObject(s, new TypeReference<ElevatorResult<ElevatorData>>() {});
        if (result.getErrorCode().equals("0") && result.getMsgType().equals("THIRDPARTY_REALTIME_DATA_RSP")) {
            if (result.getData() == null){
                //判断连接是否关闭，关闭重建连接
                return;
            }
            String regCode = result.getData().getRegisterCode();
            String eles = redisService.getCacheObject(regCode);
            if (StringUtils.isBlank(eles)){
                AfElevatorInfo param = new AfElevatorInfo();
                param.setRegisterCode(regCode);
                List<AfElevatorInfo> list = elevatorInfoService.selectAfElevatorInfoList(param);
                if (list.size() > 0 ){
                    AfElevatorInfo elevatorInfo = list.get(0);
                    ElevatorRealDataVo realDataVo = new ElevatorRealDataVo();
                    realDataVo.setElevatorInfo(elevatorInfo);
                    RealTimeData realTimeData = result.getData().getRealTimeData();
                    realDataVo.setRealTimeData(realTimeData);
                    redisService.setCacheObject(regCode, JSON.toJSONString(realDataVo));
                    ElevatorStatusVo statusVo = new ElevatorStatusVo();
                    statusVo.setElevId(elevatorInfo.getElevId());
                    statusVo.setId(elevatorInfo.getElevatorId());
                    statusVo.setErrorCode(realTimeData.get电梯故障代码());
                    statusVo.setNetStatus(realTimeData.get串口通信异常());
                    statusVo.setRepairStatus(realTimeData.get检修状态());
                    statusVo.setStatus(realTimeData.get故障状态());
                    redisService.setCacheObject(statusVo.getId(), JSON.toJSONString(statusVo));
                    mqttGateway.sendToMqtt("elevator_realData",JSON.toJSONString(realDataVo));
                    checkStatusAndPush(statusVo, realTimeData);
                }
            }else {
                ElevatorRealDataVo realDataVo = JSON.parseObject(eles, ElevatorRealDataVo.class);
                RealTimeData realTimeData = result.getData().getRealTimeData();
                realDataVo.setRealTimeData(realTimeData);
                redisService.setCacheObject(regCode, JSON.toJSONString(realDataVo));
                ElevatorStatusVo statusVo = new ElevatorStatusVo();

                statusVo.setElevId(realDataVo.getElevatorInfo().getElevId());
                statusVo.setId(realDataVo.getElevatorInfo().getElevatorId());
                statusVo.setErrorCode(realTimeData.get电梯故障代码());
                statusVo.setNetStatus(realTimeData.get串口通信异常());
                statusVo.setRepairStatus(realTimeData.get检修状态());
                statusVo.setStatus(realTimeData.get故障状态());
                statusVo.setDate(DateUtil.formatDateTime(new Date()));
                redisService.setCacheObject(statusVo.getId(), JSON.toJSONString(statusVo));
                mqttGateway.sendToMqtt("elevator_realData",JSON.toJSONString(realDataVo));
                checkStatusAndPush(statusVo, realTimeData);
            }
        }
    }

    private void checkStatusAndPush(ElevatorStatusVo statusVo, RealTimeData realTimeData){
        if (!statusVo.getStatus().equals("正常") || !statusVo.getNetStatus().equals("正常")){
            // 推送消息
            // 查询电梯信息并推送到手机端
            String id = statusVo.getId();
            AfElevator result = elevatorService.selectAfElevatorById(id);
            if (result != null){
                ElevatorStatusPushVo pushVo = new ElevatorStatusPushVo();
                pushVo.setElevator(result);
                pushVo.setElevatorStatus(statusVo);
                mqttGateway.sendToMqtt("elevator_error", JSON.toJSONString(pushVo));
                //保存故障信息
                AfElevatorError error = new AfElevatorError();
                error.setElevatorId(statusVo.getId());
                error.setElevId(statusVo.getElevId());
                error.setErrorCode(statusVo.getErrorCode());
                if (!statusVo.getNetStatus().equals("正常")){
                    error.setErrorDesc("串口通信异常");
                }
                if (!statusVo.getStatus().equals("正常")){
                    error.setErrorDesc("故障报警");
                }
                error.setErrorMsg(JSON.toJSONString(realTimeData));
                afElevatorErrorService.insertErrorMsg(error);

                ElevatorDataValue.errorList = ElevatorDataValue.errorList.stream().filter(o -> !o.getId().equals(statusVo.getId())).collect(Collectors.toList());
                ElevatorDataValue.errorList.add(statusVo);
                //存入消息
                // 插入消息表，发送人
                SysMsgAndTemplate sysMsgSend = new SysMsgAndTemplate();
                sysMsgSend.setModuleType("电梯管理");
                sysMsgSend.getParamList().add(result.getElevatorCode());
                sysMsgSend.getParamList().add(error.getErrorDesc());
                //sysMsgSend.setTemplateType(msgTemplate.getTempType());
                //sysMsgSend.setUserId(userId);
                //插入log数据库
                remoteMsgSendService.insertMsg(sysMsgSend);
            }
        }else {
            // 移除故障列表
            //ElevatorDataValue.errorList = ElevatorDataValue.errorList.stream().filter( o -> !o.getId().equals(statusVo.getId())).collect(Collectors.toList());
            for (int i = ElevatorDataValue.errorList.size() - 1; i >= 0; i--){
                if (ElevatorDataValue.errorList.get(i).getId().equals(statusVo.getId())){
                    //更新故障时长
                    AfElevatorError error = new AfElevatorError();
                    error.setId(ElevatorDataValue.errorList.get(i).getErrorId());
                    error.setErrorTime(DateUtils.getNowDate().getTime()-DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS,ElevatorDataValue.errorList.get(i).getDate()).getTime());
                    afElevatorErrorService.updateAfElevatorError(error);
                    ElevatorDataValue.errorList.remove(i);
                }
            }
            //移除离线列表
        }

    }

    public void start(){
        //监听连接是否关闭，关闭重连，实现接口；start.
    }

    @Override
    public void onClose(int code, String reason, boolean remote) {
        log.info("websocket close by " + (remote ? "remote peer" : "us") + " Code: " + code + " Reason: "
                + reason );
        //send((String)null);
        //timer.cancel();
        //有时候不起作用
/*        if(remote){
            reconnect();
            log.info("websocket 连接正常关闭,重连...");
        }*/
//        if(client.getReadyState().equals(ReadyState.OPEN)){
//            log.info("websocket 连接重连成功");
//        }else {
//            log.info("websocket 连接重连失败成功");
//        }
        //client.reconnect();
/*        if(client.getReadyState().equals(ReadyState.CLOSED)){
            log.info("websocket 连接关闭");
            WebSocketSessionManger.removeSession(webUrl.toString());
        }*/
    }

    @Override
    public void onError(Exception e) {
        log.info("websocket 异常--->{}", e.getMessage());
        //timer.cancel();
/*        //有时候不起作用，其他地方有重启
        if (getReadyState().equals(ReadyState.CLOSING) || getReadyState().equals(ReadyState.CLOSED)) {
            reconnect();
        }*/

        //WebSocketSessionManger.removeSession(webUrl.toString());
    }

}
